2.5 引用类型
所谓引用类型(reference type)特指slice、map、channel这三种预定义类型。
相比数字、数组等类型,引用类型拥有更复杂的存储结构。除分配内存外,它们还须初始化一系列属性,诸如指针、长度,甚至包括哈希分布、数据队列等。
内置函数new按指定类型长度分配零值内存,返回指针,并不关心类型内部构造和初始化方式。而引用类型则必须使用make函数创建,编译器会将make转换为目标类型专用的创建函数(或指令),以确保完成全部内存分配和相关属性初始化。
func mkslice() []int{
s:=make([]int,0,10)
s=append(s,100)
return s
}
func mkmap()map[string]int{
m:=make(map[string]int)
m["a"] =1
return m
}
func main() {
m:=mkmap()
println(m["a"])
s:=mkslice()
println(s[0])
}输出:
$go build-gcflags"-l" // 禁用函数内联
$go tool objdump-s"main\.mk"test
TEXT main.mkslice(SB)test.go
CALL runtime.makeslice(SB)
TEXT main.mkmap(SB)test.go
CALL runtime.makemap(SB)
除new/make函数外,也可使用初始化表达式,编译器生成的指令基本相同。
当然,new函数也可为引用类型分配内存,但这是不完整创建。以字典(map)为例,它仅分配了字典类型本身(实际就是个指针包装)所需内存,并没有分配键值存储内存,也没有初始化散列桶等内部属性,因此它无法正常工作。
import"fmt"
func main() {
p:=new(map[string]int) // 函数new返回指针
m:= *p
m["a"] =1 //panic:assignment to entry in nil map(运行期错误)
fmt.Println(m)
}